在 Kubernetes (K8s) 中,每個 Pod 都有自己獨立的 IP 位址。然而,直接使用 Pod IP 進行通訊會遇到兩個致命問題:
Service 正是為了解決這兩個問題而誕生的。它為一組功能相同的 Pod 提供了一個穩定、單一的虛擬存取入口。
您可以將 Service 想像成一個團隊的「總機號碼」。您只需要撥打這個固定的總機號碼,後端的接線生 (kube-proxy
) 就會自動幫您轉接到一位當前有空的客服人員 (Pod)。您完全不需要關心客服人員有多少位,或是他們的分機號碼是多少。
這個機制實現了 K8s 中兩個最重要的概念:
Service 是如何知道要將流量轉發到哪些 Pod 的呢?答案是透過 Labels 和 Selectors。
app: MyApp
。.spec.selector
中指定它要尋找帶有 app: MyApp
標籤的 Pod。kube-proxy
會監聽 EndpointSlice 的變化,並據此更新節點上的 iptables
或 IPVS
規則,實現流量的轉發。graph TD
A[Service <br> `selector: app=MyApp`] -- "Watches for Pods with label" --> B((Pod <br> `app=MyApp`));
A -- "Updates" --> C{EndpointSlice <br> `[Pod1_IP:Port, Pod2_IP:Port]`};
D(kube-proxy on each Node) -- "Watches" --> C;
D -- "Updates iptables/IPVS rules" --> E[Node's Network Rules];
類型 | 作用域 | IP 來源 | 典型用途 |
---|---|---|---|
ClusterIP |
叢集內部 | 由 K8s 分配的虛擬 IP | (預設) 叢集內部的服務間通訊。 |
NodePort |
叢集內部 + 節點 | 在每個節點上開啟一個靜態埠號 | 臨時暴露服務,用於開發或測試。 |
LoadBalancer |
叢集外部 | 由雲端供應商提供的外部負載平衡器 IP | 將服務標準化地暴露到網際網路。 |
ExternalName |
外部服務 | 一個外部的 DNS 名稱 | 在叢集內部用一個別名來代理一個外部服務。 |
ClusterIP
(預設)最常見的類型,為 Service 分配一個只能在叢集內部存取的虛擬 IP。
NodePort
在 ClusterIP
的基礎上,會在所有節點上開啟同一個埠號 (30000
-32767
)。外部流量可以透過 [任何節點 IP]:[NodePort]
來存取該服務。
LoadBalancer
在 NodePort
的基礎上,會向雲端供應商(如果有的話)申請一個外部負載平衡器。雲端 LB 會將流量導向所有節點的 NodePort
。這是將服務暴露給外部世界的標準方式。
ExternalName
一個特例。它不使用 selector
,而是直接將 Service 的 DNS 名稱,以 CNAME 的形式指向一個外部的 DNS 名稱。
當您將 Service 的 .spec.clusterIP
設為 None
時,就建立了一個 Headless Service。
kube-proxy
也不會處理它。這種模式繞過了 K8s 的負載平衡,允許客戶端直接與每個 Pod 進行通訊。它對於需要自己進行服務發現和成員管理的有狀態應用(如資料庫叢集、ZooKeeper)至關重要,也是 StatefulSet 的必要前置條件。
Service 是 K8s 網路的基石,它將動態、脆弱的 Pod 抽象成穩定、可靠的服務,是構建微服務架構不可或缺的一環。